/**
 * Copyright 2018-2019 jianggujin (www.jianggujin.com).
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.jianggujin.modulelink.util;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;

/**
 * 字符串工具
 * 
 * @author jianggujin
 *
 */
public class JStringUtils {
    public static final int INDEX_NOT_FOUND = -1;
    public static final String[] EMPTY_STRING_ARRAY = new String[0];

    /**
     * 判断是否为空白字符串
     * 
     * @param str 需要判断的字符串
     * @return 空白字符串则返回true
     */
    public static boolean isBlank(CharSequence str) {
        int strLen;
        if (str == null || (strLen = str.length()) == 0) {
            return true;
        }
        for (int i = 0; i < strLen; i++) {
            if ((Character.isWhitespace(str.charAt(i)) == false)) {
                return false;
            }
        }
        return true;
    }

    /**
     * 判断字符串是否相等
     * 
     * @param str1 字符串1
     * @param str2 字符串2
     * @return 相等则返回true
     */
    public static boolean equals(CharSequence str1, CharSequence str2) {
        return str1 == null ? str2 == null : str1.equals(str2);
    }

    /**
     * 将异常转换为字符串
     * 
     * @param throwable 异常对象
     * @return 异常信息字符串
     */
    public static String reflectionToString(Throwable throwable) {
        StringWriter sw = new StringWriter();
        PrintWriter writer = new PrintWriter(sw);
        throwable.printStackTrace(writer);
        writer.close();
        return sw.toString();
    }

    /**
     * 首字母变小写
     * 
     * @param str 需要转换的字符串
     * @return 转换结果
     */
    public static String firstCharToLowerCase(String str) {
        char firstChar = str.charAt(0);
        if (firstChar >= 'A' && firstChar <= 'Z') {
            char[] arr = str.toCharArray();
            arr[0] += ('a' - 'A');
            return new String(arr);
        }
        return str;
    }

    /**
     * 首字母变大写
     * 
     * @param str 需要转换的字符串
     * @return 转换结果
     */
    public static String firstCharToUpperCase(String str) {
        char firstChar = str.charAt(0);
        if (firstChar >= 'a' && firstChar <= 'z') {
            char[] arr = str.toCharArray();
            arr[0] -= ('a' - 'A');
            return new String(arr);
        }
        return str;
    }

    /**
     * 判断字符串中包含文本
     * 
     * @param str 需要判断的字符串
     * @return 包含文本则返回true
     */
    public static boolean hasText(CharSequence str) {
        return (!isEmpty(str) && containsText(str));
    }

    /**
     * 判断字符串中包含文本
     * 
     * @param str 需要判断的字符串
     * @return 包含文本则返回true
     */
    private static boolean containsText(CharSequence str) {
        int strLen = str.length();
        for (int i = 0; i < strLen; i++) {
            if (!Character.isWhitespace(str.charAt(i))) {
                return true;
            }
        }
        return false;
    }

    /**
     * 将字符串转换为驼峰形式
     * 
     * @param stringWithUnderline 需要转换的字符串
     * @return 驼峰形式字符串
     */
    public static String toCamelCase(String stringWithUnderline) {
        if (stringWithUnderline.indexOf('_') == -1) {
            return stringWithUnderline;
        }

        stringWithUnderline = stringWithUnderline.toLowerCase();
        char[] fromArray = stringWithUnderline.toCharArray();
        char[] toArray = new char[fromArray.length];
        int j = 0;
        for (int i = 0; i < fromArray.length; i++) {
            if (fromArray[i] == '_') {
                // 当前字符为下划线时，将指针后移一位，将紧随下划线后面一个字符转成大写并存放
                i++;
                if (i < fromArray.length) {
                    toArray[j++] = Character.toUpperCase(fromArray[i]);
                }
            } else {
                toArray[j++] = fromArray[i];
            }
        }
        return new String(toArray, 0, j);
    }

    /**
     * 字符串数组拼接
     * 
     * @param stringArray 字符串数组
     * @return 拼接后的字符串
     */
    public static String join(String[] stringArray) {
        StringBuilder sb = new StringBuilder();
        for (String s : stringArray) {
            sb.append(s);
        }
        return sb.toString();
    }

    /**
     * 字符串数组拼接
     * 
     * @param stringArray 字符串数组
     * @param separator   分隔符
     * @return 拼接后的字符串
     */
    public static String join(String[] stringArray, String separator) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < stringArray.length; i++) {
            if (i > 0) {
                sb.append(separator);
            }
            sb.append(stringArray[i]);
        }
        return sb.toString();
    }

    /**
     * 获得UUID
     * 
     * @return uuid
     */
    public static String getRandomUUID() {
        return java.util.UUID.randomUUID().toString().replace("-", "");
    }

    /**
     * 将对象转换为字符串
     * 
     * @param obj 需要转换的对象
     * @return 转换后的字符串
     */
    public static String toString(Object obj) {
        return obj == null ? null : obj.toString();
    }

    /**
     * 用提供的数据替换掉字符串中内容
     * 
     * @param text    源字符串
     * @param bindRes 替换参数
     * @return 替换后的字符串
     */
    public static String resolveDynamicPropnames(String text, Map<String, String> bindRes) {
        return resolveDynamicPropnames(text, bindRes, "${", "}");
    }

    /**
     * 用提供的数据替换掉字符串中内容
     * 
     * @param text    源字符串
     * @param bindRes 替换参数
     * @param prefix  插值前缀
     * @param suffix  插值后缀
     * @return 替换后的字符串
     */
    public static String resolveDynamicPropnames(String text, Map<String, String> bindRes, String prefix,
            String suffix) {
        if (text == null) {
            return text;
        }
        int startIndex = text.indexOf(prefix);
        if (startIndex == -1) {
            return text;
        }

        String tempStr = text;
        StringBuilder result = new StringBuilder(text.length() + 32);
        int prefixLength = prefix.length();
        while (startIndex != -1) {
            result.append(tempStr.substring(0, startIndex));
            int endIndex = tempStr.indexOf(suffix, startIndex + prefixLength);
            if (endIndex != -1) {
                String dName = tempStr.substring(startIndex + prefixLength, endIndex);
                try {
                    String pValue = null;
                    if (bindRes != null) {
                        Object obj = bindRes.get(dName);
                        if (obj != null) {
                            pValue = String.valueOf(obj);
                        }
                    }
                    if (pValue != null) {
                        result.append(resolveDynamicPropnames(pValue, bindRes));
                    } else {
                        result.append(tempStr.substring(startIndex, endIndex + 1));
                    }

                } catch (Throwable ex) {
                }
                tempStr = tempStr.substring(endIndex + suffix.length());
                startIndex = tempStr.indexOf(prefix);
            } else {
                tempStr = tempStr.substring(startIndex);
                startIndex = -1;
            }
        }
        result.append(tempStr);

        return result.toString();
    }

    /**
     * 向字符串数组最后添加字符串
     * 
     * @param array 源字符串数组
     * @param str   添加的字符串
     * @return 新的字符串数组
     */
    public static String[] addStringToArray(String[] array, String str) {
        if (array == null || array.length == 0) {
            return new String[] { str };
        }
        String[] newArr = new String[array.length + 1];
        System.arraycopy(array, 0, newArr, 0, array.length);
        newArr[array.length] = str;
        return newArr;
    }

    /**
     * 判断字符串是否为空字符串
     * 
     * @param str 需要你判断的字符串
     * @return 空字符串则返回你true
     */
    public static boolean isEmpty(CharSequence str) {
        return str == null || str.length() == 0;
    }

    /**
     * 判断指定字符在目标字符串中的索引位置
     * 
     * @param str        源字符串
     * @param searchChar 搜索字符
     * @param startPos   开始位置
     * @return 字符索引位置
     */
    public static int indexOf(String str, char searchChar, int startPos) {
        if (isEmpty(str)) {
            return INDEX_NOT_FOUND;
        }
        return str.indexOf(searchChar, startPos);
    }

    /**
     * 拆分字符串
     * 
     * @param str       需要拆分的字符串
     * @param delimiter 分隔符
     * @return 拆分后的字符串数组
     */
    public static String[] separateString(String str, String delimiter) {
        return separateString(str, delimiter, false);
    }

    /**
     * 拆分字符串
     * 
     * @param str       需要拆分的字符串
     * @param delimiter 分隔符
     * @param trim      是否需要移除前后空白字符
     * @return 拆分后的字符串数组
     */
    public static String[] separateString(String str, String delimiter, boolean trim) {
        if (str == null) {
            return null;
        } else {
            int count = str.length();
            if (count == 0) {
                return EMPTY_STRING_ARRAY;
            } else {
                if (isEmpty(delimiter)) {
                    delimiter = " \t\n\r\f";
                }

                ArrayList<String> list = new ArrayList<String>();
                int i = 0;
                int begin = 0;
                boolean notMatch = false;
                if (delimiter.length() == 1) {
                    char c = delimiter.charAt(0);
                    while (i < count) {
                        if (str.charAt(i) == c) {
                            if (notMatch) {
                                list.add(trim ? str.substring(begin, i).trim() : str.substring(begin, i));
                                notMatch = false;
                            }
                            ++i;
                            begin = i;
                        } else {
                            notMatch = true;
                            ++i;
                        }
                    }
                } else {
                    while (i < count) {
                        if (delimiter.indexOf(str.charAt(i)) >= 0) {
                            if (notMatch) {
                                list.add(trim ? str.substring(begin, i).trim() : str.substring(begin, i));
                                notMatch = false;
                            }
                            ++i;
                            begin = i;
                        } else {
                            notMatch = true;
                            ++i;
                        }
                    }
                }
                if (notMatch) {
                    list.add(trim ? str.substring(begin, i).trim() : str.substring(begin, i));
                }
                return (String[]) list.toArray(new String[list.size()]);
            }
        }
    }

    public static String[] tokenizeToStringArray(String str, String delimiters, boolean trimTokens,
            boolean ignoreEmptyTokens) {

        if (str == null) {
            return new String[0];
        }

        StringTokenizer st = new StringTokenizer(str, delimiters);
        List<String> tokens = new ArrayList<String>();
        while (st.hasMoreTokens()) {
            String token = st.nextToken();
            if (trimTokens) {
                token = token.trim();
            }
            if (!ignoreEmptyTokens || token.length() > 0) {
                tokens.add(token);
            }
        }
        return toStringArray(tokens);
    }

    public static String[] toStringArray(Collection<String> collection) {
        return collection.toArray(new String[0]);
    }

    /**
     * 格式化字符串
     * 
     * @param message
     * @param args
     * @return
     */
    public static String format(String message, Object... args) {
        if (args.length > 0) {
            return JMessageFormatter.arrayFormat(message, args).getMessage();
        }
        return message;
    }
}
